package com.ch3cooh.rpc.util;

import com.ch3cooh.registry.service.ZkService;
import com.ch3cooh.rpc.annotation.HttpRpc;
import com.ch3cooh.test.TestService;
import com.ch3cooh.test.TestServiceImpl;
import lombok.extern.java.Log;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * @功能:
 * @作者:chanson
 * @时间:2018/5/1 20:57
 */
@Log
public class ScannerUtils {

    private interface WhatDo{
        void execute(File file, Class<?> clazz);
    }

    /**
     * 获取项目工程的根目录
     * @param iPackage  "扫描包"
     * @return
     */
    private static String getProjectRootPath(String iPackage){
        String path = iPackage.replace(".", "/");
        URL url = Thread.currentThread().getContextClassLoader().getResource(path);
        int target = url.getFile().indexOf("/target");
        String path0 = url.getFile().substring(0,target);
        int i = path0.lastIndexOf('/');
        String path1 = path0.substring(0,i+1);
        return path1;
    }

    public static void scanPackage(String iPackage,WhatDo what){
        String rootPath =getProjectRootPath(iPackage);
        try {
            if(rootPath!=null ){
                String filePath = URLDecoder.decode(rootPath,"utf-8");
                File dir = new File(filePath);
                List<File> fileList = new ArrayList<File>();
                fetchFileList(dir,fileList);
                for(File f:fileList){
                    String fileName =  f.getAbsolutePath();
                    if(fileName.endsWith(".class")){
                  //     System.err.println(fileName);
                        //fileName一般的形式如此: D:/ideaWorkspace/fromGitee/zookeeper-curator-l-11/registry/target/classes/com/ch3cooh/registry/test
                        // 要+8是指从/classes/com/ch3cooh...的 com/ch3cooh开始
                        String nosuffixFileName = fileName.substring(8+fileName.lastIndexOf("classes"),fileName.indexOf(".class"));
                        String filePackage = nosuffixFileName.replaceAll("\\\\", ".");
                        //动态加载类
                        try {
                            //通过异常来控制逻辑，性能会降低
                            Class<?> clazz = Class.forName(filePackage);
                            what.execute(f,clazz);
                        }catch (Exception e){
                        }

                    }else{
                        what.execute(f,null);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 递归调用将所有文件放到一个List集合中
     * @param dir
     * @param fileList
     */
    private static void  fetchFileList(File dir,List<File> fileList){
        if(dir.isDirectory()){
            for(File f:dir.listFiles()){
                fetchFileList(f,fileList);
            }
        }else{
            fileList.add(dir);
        }
    }

    /**
     * 扫描包下的所有接口(不包含 注解、内部接口、成员变量接口)
     * @param packageName
     * @return
     */
    public static List<Class> scanInterface(String packageName){
        List<Class> interfaces = new ArrayList<>();
        scanPackage(packageName, new WhatDo() {
            @Override
            public void execute(File file, Class<?> clazz) {
                if(clazz!=null && clazz.isInterface() && !clazz.isAnnotation() && !clazz.isLocalClass() && !clazz.isMemberClass() ){
                    interfaces.add(clazz);
                }
            }
        });
        return interfaces;
    }

    /**
     * 扫描包下的所有实现类
     * @param packageName
     * @return
     */
    public static List<Class> scanInterfaceImlp(String packageName){
        List<Class> interfaces = new ArrayList<>();
        scanPackage(packageName, new WhatDo() {
            @Override
            public void execute(File file, Class<?> clazz) {
                if(clazz!=null && !clazz.isInterface() &&  clazz.getName().toLowerCase().lastIndexOf("impl")!=-1 ){
                    interfaces.add(clazz);
                }
            }
        });
        return interfaces;
    }

    /**
     * 封装成一个map  key为接口、value为对应的实现类
     * @param packageName
     * @return
     */
    public static Map<String,List<Class>> mapInterfaceImpl(String packageName){
        List<Class> interfaces = scanInterface(packageName);
        List<Class> impls = scanInterfaceImlp(packageName);
        Map<String,List<Class>> map = new HashMap<>();
        for(Class i : interfaces) {
            ArrayList<Class> cList = new ArrayList<>(impls.size()+1);
            map.put( i.getName(), cList);
            for(Class impl : impls){
                if( i.isAssignableFrom(impl)){
                    cList.add(impl);
        //            impls.remove(impl);
                }
            }
        }
        return map;
    }

    /**
     * 扫描包的指定注解的接口
     * @param packageName
     * @param tClass
     * @return
     */
    public static List<Class> scanInterfaceByAnnotation(String packageName, Class tClass){
        List<Class> classes = scanInterface(packageName).parallelStream().filter(e->e.getDeclaredAnnotation(tClass)!=null).collect(Collectors.toList());
        if(classes.size() == 0) log.info("[scanInterfaceByAnnotation] no result on scanning");
        return classes;
    }

    public static void main(String[] args) {

        mapInterfaceImpl("").forEach( (k,v)->{
            System.out.println( k + " : " + Arrays.toString( v.toArray() ));
        } );  //.forEach(System.out::println);

       // System.out.println(       ZkService.class.isAssignableFrom(TestServiceImpl.class) );
    }






}
